package com.hksj.gas.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hksj.base.service.DefaultDeviceService;
import com.hksj.cbm.entity.DeviceInstance;
import com.hksj.cbm.service.DeviceInstanceService;
import com.hksj.cbm.vo.SpaceModelVO;
import com.hksj.common.core.common.ProductTypeEnum;
import com.hksj.common.core.common.SpecialityModelCodeEnum;
import com.hksj.gas.dto.GasLargeScreenDTO;
import com.hksj.gas.mapper.GasLargeScreenMapper;
import com.hksj.gas.vo.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class GasLargeScreenService {

    private static final Logger log = LoggerFactory.getLogger(GasLargeScreenService.class);

    @Autowired
    private GasLargeScreenMapper gasLargeScreenMapper;

    @Autowired
    private DeviceInstanceService deviceInstanceService;

    @Autowired
    private DefaultDeviceService defaultDeviceService;

    /**
     * 根据传入的DTO查询天然气设备统计数据。
     *
     * @param dto 大屏幕展示数据传输对象，包含查询条件。
     * @return GasDeviceStatsVO 统计数据的视图对象，包含总的设备统计数据和按类型分类的设备统计数据。
     */
    public GasDeviceStatsVO queryGasDeviceStats(GasLargeScreenDTO dto) {
        //添加专业code
        dto.setCode(SpecialityModelCodeEnum.medical_gas.getCode());
        // 通过mapper查询总的医用气体设备统计数据
        GasDeviceStatsVO vo=gasLargeScreenMapper.queryGasDeviceStats(dto);
        // 通过mapper查询按类型分类的医用气体设备统计数据
        List<GasDeviceStatsByTypeVO>list=gasLargeScreenMapper.queryGasDeviceStatsByType(dto);
        // 将code转化为名称
        if (!CollectionUtils.isEmpty(list)){
            list.forEach(item->{
                item.setClassifiedName(ProductTypeEnum.getValueByType(item.getClassifiedCode()));
            });
        }
        // 将分类的设备统计数据设置到总的统计数据视图对象中
        vo.setDeviceStatsByTypeVOList(list);
        // 返回包含总数据和分类数据的视图对象
        return vo;
    }

    /**
     * 根据传入的条件查询气体设备统计数据列表，并分页返回结果。
     *
     * @param dto 查询条件对象，包含分页信息和筛选条件。
     * @return 返回分页后的气体设备统计数据列表。
     */
    public IPage<GasDeviceStatsListVO> queryGasDeviceStatsList(GasLargeScreenDTO dto) {
        // 初始化分页对象，传入当前页码和每页大小
        IPage<GasDeviceStatsListVO> page= new Page<>(dto.getPageNum(),dto.getPageSize());

        //添加专业code
        dto.setCode(SpecialityModelCodeEnum.medical_gas.getCode());

        // 调用Mapper查询气体设备统计数据列表，同时传入分页对象进行分页查询
        List<GasDeviceStatsListVO>list=gasLargeScreenMapper.queryGasDeviceStatsList(dto,page);

        // 将查询结果设置到分页对象中
        page.setRecords(list);

        // 返回分页后的查询结果
        return page;
    }

    /**
     * 根据日期查询设备的气体流量
     *
     * @param dto GasLargeScreenDTO类型的参数，包含查询条件
     * @return 返回一个List，包含ProductFlowTypeVO类型的元素，每个元素代表一种产品的流量类型
     */
    public List<ProductFlowTypeVO> queryDeviceGasFlowByDate(GasLargeScreenDTO dto) {
        // 创建一个ProductFlowTypeVO对象，用于存储氧气的流量信息
        ProductFlowTypeVO vo = new ProductFlowTypeVO();
        vo.setProductId(ProductTypeEnum.Yiqll_Yangq_product.getType());
        vo.setProductName(ProductTypeEnum.Yiqll_Yangq_product.getValue());

        //添加专业code
        dto.setCode(SpecialityModelCodeEnum.medical_gas.getCode());

        // 初始化一个SimpleDateFormat对象，用于日期格式化
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 获取当前日期的Calendar实例
        Calendar calendar = Calendar.getInstance();

        // 生成最近七天的日期列表
        List<String> recentDates = Stream.iterate(0, n -> n + 1)
                .limit(7)
                .map(n -> {
                    Calendar cal = (Calendar) calendar.clone();
                    cal.add(Calendar.DAY_OF_MONTH, -n);
                    return sdf.format(cal.getTime());
                })
                .sorted()
                .collect(Collectors.toList());

        // 根据日期列表创建GasDeviceTimeVO对象列表
        List<GasDeviceTimeVO> flowList = recentDates.stream()
                .map(date -> {
                    GasDeviceTimeVO gasDeviceTimeVO = new GasDeviceTimeVO();
                    gasDeviceTimeVO.setTs(date);
                    return gasDeviceTimeVO;
                }).collect(Collectors.toList());

        // 将flowList设置到oxygenVO对象中
        vo.setFlowList(flowList);

        // 查询当前区域位置下是否存在氧气流量监测设备
        List<DeviceInstance> list = gasLargeScreenMapper.queryGasProductId(dto);
        // 如果没有找到相关设备，则直接返回只包含oxygenVO的列表
        if (CollUtil.isEmpty(list)){
            return Collections.singletonList(vo);
        }

        // 获取设备的产品ID对应的数据库表名
        String tableName = defaultDeviceService.getTableName(list.get(0).getProductId());
        // 获取所有设备的ID列表
        List<String> deviceIdList = list.stream().map(DeviceInstance::getId).collect(Collectors.toList());

        // 尝试从数据库查询氧气流量数据
        try {
            // 查询指定表和设备ID列表的每日流量数据
            List<ProductFlowVO> dailyFlowList = gasLargeScreenMapper.queryProductIdDailyFlow(tableName, deviceIdList);
            // 如果查询到流量数据不为空，则进行处理
            if (!CollectionUtils.isEmpty(dailyFlowList)) {
                // 将流量数据按时间戳汇总
                Map<String, Double> map = dailyFlowList.stream()
                        .collect(Collectors.toMap(ProductFlowVO::getTs, ProductFlowVO::getFlow, Double::sum));
                // 将汇总的流量数据填充到flowList中
                flowList.forEach(item ->{
                    if (map.containsKey(item.getTs())){
                        Double value = map.get(item.getTs());
                        item.setVal(Math.round(value * 100.0) / 100.0);
                    }
                });

                // 更新oxygenVO对象中的流量列表
                vo.setFlowList(flowList);
            }
        } catch (Exception e){
            // 如果查询数据库失败，则记录错误日志
            log.error("查询tdengine数据库失败", e);
        }

        // 返回只包含oxygenVO的列表作为查询结果
        return Collections.singletonList(vo);
    }



    /**
     * 根据传入的LargeScreenDTO查询气体报警设备及其详情。
     * 该方法首先通过largeScreenMapper查询气体报警设备的统计概况，然后查询设备的详细报警信息列表。
     * 接着，对详细报警信息中的路径进行处理，转换为UTF-8编码。最后，将处理后的详细信息列表设置到统计概况中并返回。
     *
     * @param dto 大屏幕数据传输对象，用于传递查询条件。
     * @return GasAlarmDeviceVO 对气体报警设备的统计概况及详情的封装对象。
     */
    public GasAlarmDeviceVO queryAlarmDevice(GasLargeScreenDTO dto) {
        // 根据dto查询气体报警设备的统计概况
        GasAlarmDeviceVO vo=gasLargeScreenMapper.queryAlarmDevice(dto);
        if (ObjectUtils.isEmpty(vo)) {
            return null; // 如果查询结果为空，直接返回null
        }
        // 根据dto查询气体报警设备的详细报警信息列表
        List<GasAlarmDeviceDetailsVO>list=gasLargeScreenMapper.queryGasAlarmDeviceDetailsList(dto);
        // 将详细报警信息列表设置到统计概况中
        vo.setAlarmsDetailsVOList(list);

        // 将详细信息中的路径提取出来，形成一个路径列表
        List<String> pathList = list.stream()
                .map(GasAlarmDeviceDetailsVO::getPaths)
                .filter(paths -> !ObjectUtils.isEmpty(paths))
                .collect(Collectors.toList());

        // 如果路径列表为空，则直接返回统计概况
        if (CollUtil.isEmpty(pathList)){
            return vo;
        }

        // 将路径列表转换为UTF-8编码的设备空间模型列表
        Map<String, List<SpaceModelVO>> pathNameMap = deviceInstanceService.devicePathConvertToUTF8(pathList);
        // 如果转换后的设备空间模型列表不为空，则将其设置到详细报警信息中
        if (CollUtil.isNotEmpty(pathNameMap)){
            // 遍历详细报警信息列表，为每个设备设置其空间模型列表
            list.forEach(alarmVO -> {
                alarmVO.setSpaceModelVOList(pathNameMap.get(alarmVO.getPaths()));
            });
            // 更新统计概况中的详细报警信息列表
            vo.setAlarmsDetailsVOList(list);
        }

        // 返回包含详细报警信息的气体报警设备统计概况
        return vo;
    }


    /**
     * 最近七天报警数
     *
     * @param dto 查询参数对象，包含开始时间和结束时间
     * @return 返回一个包含GasHistoryAlarmDeviceVO对象的列表
     */
    public List<GasHistoryAlarmDeviceVO> queryGasHistoryAlarmDeviceByTime(GasLargeScreenDTO dto) {
        // 根据开始时间和结束时间生成每天的时间列表
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        // 生成最近七天的日期列表
        List<String> timeList = Stream.iterate(0, n -> n + 1)
                .limit(7)
                .map(n -> {
                    Calendar cal = (Calendar) calendar.clone();
                    cal.add(Calendar.DAY_OF_MONTH, -n);
                    return sdf.format(cal.getTime());
                })
                .sorted()
                .collect(Collectors.toList());
        // 根据时间列表生成一个初步的GasHistoryAlarmDeviceVO列表，每个VO包含一个时间
        List<GasHistoryAlarmDeviceVO> list = timeList.stream().map(time -> {
            GasHistoryAlarmDeviceVO vo = new GasHistoryAlarmDeviceVO();
            vo.setAlarmTime(time);
            return vo;
        }).collect(Collectors.toList());
        // 从数据库查询燃气历史报警设备数据
        List<GasHistoryAlarmDeviceVO> alarmList = gasLargeScreenMapper.queryGasHistoryAlarmDeviceByTime(dto);
        // 如果查询结果不为空，则将其转换为一个以报警时间为键的Map
        if(!CollectionUtil.isEmpty(alarmList)) {
            Map<String, GasHistoryAlarmDeviceVO> map = alarmList.stream()
                    .collect(Collectors.toMap(GasHistoryAlarmDeviceVO::getAlarmTime, Function.identity()));
            // 将查询结果中的数据合并到初步的VO列表中
            list.forEach(vo -> {
                if (map.containsKey(vo.getAlarmTime())) {
                    GasHistoryAlarmDeviceVO alarmVO = map.get(vo.getAlarmTime());
                    vo.setOverpressureAlertCount(alarmVO.getOverpressureAlertCount());
                    vo.setUnderVoltageAlertCount(alarmVO.getUnderVoltageAlertCount());
                }
            });
        }
        // 返回最终的GasHistoryAlarmDeviceVO列表
        return list;
    }


    //最近七天报警设备分类
    public List<GasAlarmDeviceTypeVO> queryGasAlarmDeviceByType(GasLargeScreenDTO dto) {
        //查询报警类别
        List<GasAlarmDeviceTypeVO> list = gasLargeScreenMapper.queryGasDeviceType();
        List<GasAlarmDeviceTypeVO> alarmList = gasLargeScreenMapper.queryGasAlarmDeviceByType(dto);
        if(!CollectionUtil.isEmpty(alarmList)) {
            Map<String, GasAlarmDeviceTypeVO> map = alarmList.stream()
                    .collect(Collectors.toMap(GasAlarmDeviceTypeVO::getClassifiedId, Function.identity()));
            list.forEach(vo -> {
                if (map.containsKey(vo.getClassifiedId())) {
                    GasAlarmDeviceTypeVO alarmVO = map.get(vo.getClassifiedId());
                    vo.setAlarmNum(alarmVO.getAlarmNum());
                }
            });

        }
        return list;
    }
}































